iT邦幫忙

2022 iThome 鐵人賽

DAY 21
0
自我挑戰組

在30天利用HTML & CSS & JavaScript完成Side Project實作系列 第 21

Day 21 Side Project : Password Generator 密碼生成器(下)

  • 分享至 

  • xImage
  •  


接續Day 20,繼續來講解沒完成的JS部分


專案回顧

https://ithelp.ithome.com.tw/upload/images/20220926/20149362kYLbgJlrTe.png

畫面和功能拆解

  • 畫面中的密碼生成器裡內有標題 > 結果顯示欄 +複製按鈕 > 需求設定 > 生成按鈕(Generate Password)
  • 點擊生成按鈕(Generate Password)會隨機產生不同的密碼
  • 按下複製,會出現"copied"的訊息

運用知識點羅列

  • JS
知識點 使用說明
Number() 在此將字串轉換為數字
filter() 篩選符合條件的元素
Object.values( ) 將物件的放入陣列中回傳
Object.keys() 將物件的屬性放入陣列中回傳
slice() 擷取從起始點到終點間(不含終點)範圍內的元素
createElement 在此用於創建一件複製的<textarea>標籤
Clipboard.writeText 複製的功能核心
async await / promise 處理一鍵複製按鈕的非同步事件

流程講解 (若想看CSS和HTML請點這)

  • JS
    功能分解
//密碼生成按鈕
generateEl.addEventListener("click", () => {
  let length = Number(lengthEl.value); //或  +lengthEl.value
  let hasLower = lowercaseEl.checked;
  let hasUpper = uppercaseEl.checked;
  let hasNumber = numbersEl.checked;
  let hasSymbol = symbolsEl.checked;
  console.log(hasLower, hasUpper, hasNumber, hasSymbol); //布林值
  resultEl.innerText = generatePassword(hasLower, hasUpper, hasNumber, hasSymbol,length);
    
})

變數 length 存放的是輸入框的值(如下圖),用戶輸入什麼就是什麼,另外要注意的是,因為 type="text" ,所以value傳回的值會是字串,使用 Number( ) 將之轉換為數字,或是在前面加個 + 號也是可以
https://ithelp.ithome.com.tw/upload/images/20220927/20149362AbkGn8Rahw.png

後面四個變數為複選框checkbox(如下圖),所以可以去檢查有沒有 checked 屬性,回傳值是布林值,有被勾選會是 true ;沒被勾選會是 false
https://ithelp.ithome.com.tw/upload/images/20220927/201493628rPOoSreV5.png
最後的resultEl,為密碼生成結果,因為它會受上面那五個變數影響,所以我們創建一個函式叫做generatePassword()去接收這些變數的值,並讓他去做我們要他做的事

創建去接收用戶的選擇的函數

//擷取上段程式碼,僅為了增加易讀性
resultEl.innerText = generatePassword(hasLower, hasUpper, hasNumber, hasSymbol,length);

function generatePassword(lower, upper, number, symbol, length) {
  let generatedPassword = ""; //默認下為空值
  let typesCount = lower + upper + number + symbol;
  let typesArr = [{ lower }, { upper }, { number }, { symbol }]
  console.log(typesArr);
}

變數typesCount是由布林值相加而成,true=1 false=0,如下圖假設有2個輸入框被選取,就代表有2個true, typesCount 就等於2
https://ithelp.ithome.com.tw/upload/images/20220927/20149362OI6ajoKB6H.png

let typesArr = [{ lower }, { upper }, { number }, { symbol }]; 用來存放數筆資料,{lower} 其實跟 {lower:lower} 是一樣的,在ES6中可以簡寫為 {lower}

接著我們用 filter()並傳入arrow function作為參數去處理 typesArr變數

  let typesArr = [{ lower }, { upper }, { number }, { symbol }].filter(
  item =>Object.values(item)[0]);

上面這段程式碼拆成以下兩個知識點進行補充說明

Array.prototype.filter( )

The filter() method creates a shallow copy of a portion of a given array, filtered down to just the elements from the given array that pass the test implemented by the provided function.

擷取MDN上的解釋

陣列處理方法filter() 可以想像成麵粉拿去過篩,我們將一大包麵粉過篩去除雜質後得到一盆新的麵粉,套用在程式中,就是原陣列篩選出符合該函式條件的元素後會回傳一個新陣列給你。淺拷貝( [shallow copy](Shallow copy) )是指原資料和拷貝的新資料參考相同的記憶體位置,所以當原資料改變時,新的資料也會跟著改變,彼此沒有獨立性

語法:array.filter(function(currentValue, index, arr), thisValue)

Object.values( )

The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop.

擷取MDN上的解釋

Object.values()這個物件處理方法,會依照順序把物件中的值(value)放入陣列中回傳,注意O要大寫
下方是MDN上的範例
https://ithelp.ithome.com.tw/upload/images/20220927/20149362t2iy768ggE.png

語法:Object.values(obj)

用戶選取的判斷

//以下兩個變數只是為了方便閱讀貼到這裡
let randomFunc = {
  lower: getRandomLower,
  upper: getRandomUpper,
  number: getRandomNumber,
  symbol: getRandomSymbol,
};
let typesCount = lower + upper + number + symbol;


if (typesCount === 0) {
    return "";
  }
 for (let i = 0; i < length; i++) {
    typesArr.forEach((type) => {
      console.log(type);    //{lower:true} {upper:true}...
      let funcName = Object.keys(type)[0]; 
      console.log(funcName);   // lower upper number symbol
      generatedPassword += randomFunc[funcName]();
    });
  }

這段稍微複雜,如果 typesCount === 0 代表用戶沒有勾選任何複選框和輸入,就會回傳空的結果
我們利用lower upper number symbol 這四個key name帶入randomFunc物件中去執行對應的函式

Object.keys()

The Object.keys() method returns an array of a given object's own enumerable property names, iterated in the same order that a normal loop would.

擷取MDN上的解釋

Object.values()這個物件處理方法,會依照順序把物件中的屬性(key)放入陣列中回傳,注意O要大寫
下方是MDN上的範例
https://ithelp.ithome.com.tw/upload/images/20220927/201493628RNHjv0Tg4.png

語法:Object.keys(obj)

Array.prototype.slice( )

圖片來源於此

The slice() method returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included) where start and end represent the index of items in that array. The original array will not be modified.
擷取MDN上的解釋

slice()這個陣列處理方法,會以淺拷貝( [shallow copy](Shallow copy) )的方式複製從起始點到終點間(不含終點)範圍內的元素放入一個新陣列並回傳,不會修改到原陣列,下方是MDN上的範例
https://ithelp.ithome.com.tw/upload/images/20220927/20149362eX8EmP9uCo.png

語法: slice(start, end)

複製按鈕

copiedEl.addEventListener("click", async () => {
  let textArea = document.createElement("textarea");
  let password = resultEl.innerText;
  if (!password) {
    return; //不執行任何操作
  }
  await navigator.clipboard.writeText(result.innerText);
  alert("copied");
});

clipboard 指的是瀏覽器中的系統剪貼簿,要取得瀏覽器的 clipboard 物件,只要訪問 navigator 底下的 clipboard 屬性即可,執行後會回傳 Promise,我們使用async await去優化非同步語法


附上codepen連結 https://codepen.io/hangineer/pen/yLjpxVb?editors=1010

補充

1.深度了解淺拷貝(Shallow Copy) VS 深度拷貝(Deep Copy)


summary 總結

這篇有很多很重要的知識點,如果要總結大概就是陣列的處理方法和promise與async await之間的關係
若有解說不夠詳盡或是錯誤歡迎指教,感激不盡!那明天見囉


參考資料

50 Projects In 50 Days - HTML, CSS & JavaScript
那些被忽略但很好用的 Web API / Clipboard


上一篇
Day 20 Side Project : Password Generator 密碼生成器(上)
下一篇
Day 22 Side Project : Hoverboard 面板
系列文
在30天利用HTML & CSS & JavaScript完成Side Project實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
112182ssss
iT邦新手 4 級 ‧ 2023-11-16 20:02:37

不好意思,codepen上的成果按下按鈕沒有生成密碼

hannnahTW iT邦新手 2 級 ‧ 2023-11-16 20:49:48 檢舉

https://ithelp.ithome.com.tw/upload/images/20231116/20149362bjnHV7FYw2.png

哈囉~我不太確定你的使用情境
但我猜是因為上圖中密碼長度欄位的10是placeholder,必須自己去手動選擇你要的密碼長度,如果沒選就按下生成按鈕,密碼長度預設為0,所以才導致密碼沒有被生成

不過後來我加上了value="10",感覺使用上會更方便一點,你可以再試試看喔!謝謝😊

原來是因為沒有手動調整密碼長度才沒有顯示出密碼,感謝回復~~

我要留言

立即登入留言